package com.company;

import java.io.IOException;

public class C09Jvm {
//    // 虚拟机栈的演示
//    public static void main(String[] args){
//        method1();
//    }
//    public static void method1(){
//
//        Integer a =1;
//        Integer b=1;
//        System.out.println(a==b);
//        Integer c=method2(a,b);
//    }
//    public static Integer method2(Integer a,Integer b){
//        a=3;
//        return a+b;
//
//    }
// 虚拟机栈内存溢出Edit Configurations VM options: -Xss256K
//        案例:递归  不停调用方法，方法运行时内存是放在虚拟机栈中的。
// 堆内存溢出Edit Configurations VM options: -Xmx8m
//      案例：无限循环 给Arraylist添加
// 方法区：元空间内存溢 溢出Edit Configurations VM options: -XX:MaxMetaspaceSize=8m
//        案例：继承类加载器，无限加载类

    //    方法区：运行时常量池 StringTable
    // StringTable HashTable 【"a","b","ab"】
   /* public static void main(String[] args) {
        String s1="a"; // 保存到串池中 执行到才放入串池，如果有了就不会放入串池。
        String s2="b"; // 保存到串池中
        String s3="ab"; // 保存到串池中

        // s4保存到堆中
        String s4= s1+s2; // new StringBuilder().append("a").append("b").tostring()// tostring() 其实是new String()
        s4.intern();

        System.out.println(s3==s4);  // false
        String s5="a" +"b"; // 在串池中已经有了"ab"字符串对象 不需要StringBuilder拼接，编译器已经优化。
        System.out.println(s3==s5);  // true

        String s6= new String("a") + new String("b");
        //串池中 ：["a","b"]； 堆中 new String("a") ,new String("b") ， new String("ab")-》值存在堆中
        String s7="ab";// 1
        //串池中 ：["a","b"，"ab"]； 堆中 new String("a") ,new String("b") ，s6 new String("ab")-》值存在堆中
        s6.intern();//以使用intern方法，主动将串池中还没有的字符串放到串池中,【成功后？？】并且返回这个对象的引用。此时s6指向 串池中“ab”对象的引用
//        s7="ab";  // 2:
        System.out.println(s6=="ab"); //  1 是false  ; 2 是true ； （1和2都注释掉）：true ； 加上 s6=s6.intern()是true 强制"ab"引用不管有无成功

    }*/

    //    方法区：运行时常量池 StringTable 内存溢出 1.8 开始 StringTable是放在堆立面的。
//     堆内存设置1.8：Edit Configurations VM options:-Xmx10m -XX:-UseGCOverheadLimit（关闭限制）
   /* public static void main(String[] args){
         Integer i=0;
        try{
        List<String> list =new ArrayList<>();
        for( i=0 ;i<260000;i++){
            list.add(i.toString());
        }}
        catch(Throwable ex){
            ex.printStackTrace();
        }finally {
            System.out.println(i.toString());
        }
    }*/
    // JDK1.8   方法区：运行时常量池 StringTable 垃圾回收。
    //堆内存设置1.8：Edit Configurations VM options:-Xmx10m -XX:+PrintStringTableStatistics -XX:+PrintGCDetails -verbose:gc
//    public static void main(String[] args){
//        int i=0;
//
//        try{
//
//            for(  i=1 ;i<10100;i++){
//               String.valueOf(i).intern(); // StringTable statistics: Number of entries 并没有1万多个，被GC了
//            }
//        }
//        catch(Throwable ex){
//            ex.printStackTrace();
//        }finally {
//            System.out.println(i);
//
//        }
//    }
    //堆内存设置1.8：Edit Configurations VM options:-Xmx10m -XX:+PrintStringTableStatistics -XX:+PrintGCDetails -verbose:gc -XX:StringTableSize=10000
//   -XX:StringTableSize=10000 桶的个数调大 这样速度快点
//    public static void main(String[] args){
//        int i=0;
//        long start=System.nanoTime(); // 纳秒
//        try{
//
//            for(  i=1 ;i<900100;i++){
//                String.valueOf(i).intern(); // StringTable statistics: Number of entries 并没有900100万多个，被GC了
//            }
//        }
//        catch(Throwable ex){
//            ex.printStackTrace();
//        }finally {
//            System.out.println(i);
//            System.out.println((System.nanoTime()-start)/1000000);// 花费毫秒
//        }
//    }

//    直接内存
//    系统内存溢出案例
/*    static int _100MB=1024*1024*100;
    public static void main(String[] args){
        Integer a=1;
        Integer b=1;
        System.out.println(a==b);
        long start=System.nanoTime();
        List<ByteBuffer> list= new ArrayList<>();
        int i=0;
        try{
            while(true){
                ByteBuffer byteBuffer= ByteBuffer.allocateDirect(_100MB);
                list.add(byteBuffer);
                i++;
            }
        }
        finally {
            System.out.println(i);
        }
    }*/
//    直接内存
//    系统内存回收  System.gc();
/*static int _1GB=1024*1024*1024;
    public static void main(String[] args){
        Integer a=1;
        Integer b=1;
        System.out.println(a==b);
        long start=System.nanoTime();
        List<ByteBuffer> list= new ArrayList<>();

        try{
                 ByteBuffer byteBuffer= ByteBuffer.allocateDirect(_1GB);
                System.out.println("内存分配完毕");
                System.in.read();
                System.out.println("开始释放");
                byteBuffer=null;
                System.out.println("byteBuffer=null释放完毕");// byteBuffer=null内存没有被立即释放
                System.in.read();
                System.gc();
                System.out.println("System.gc释放完毕"); // System.gc()执行完后内存被释放 。原理是怎样的 :unsafe()
                System.in.read();
                list.add(byteBuffer);

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
        }
    }*/
//    直接内存
//    系统内存回收 底层原理： 使用Unsafe 对象完成直接内存的分配和回收，并且回收需要主动调用freeMemory方法
//        例如：ByteBuffer的实现类内部 ，使用了Cleaner（虚引用）来检测ByteBuffer对象，一旦ByteBuffer被
//              系统垃圾回收，那么就会由ReferenceHandler 线程通过Cleaner的clean方法调用freeMemory来释放直接内存
//    -XX:+DisableExplicitGC 显示的 System.gc()方法无效。所以我们一般用Unsafe
//static int _1GB=1024*1024*1024;
//    public static void main(String[] args){
//        try{
//            Unsafe unsafe= getUnsafe();
//
//           // 分配内存
//            long base= unsafe.allocateMemory(_1GB); // base：内存地址
//            unsafe.setMemory(base,_1GB,(byte) 0);
//            System.out.println("内存分配完毕");
//            System.in.read();
//           // 释放内存
//            unsafe.freeMemory(base);
//            System.out.println("内存释放完毕");
//            System.in.read();
//        } catch (IllegalAccessException e) {
//            e.printStackTrace();
//        } catch (NoSuchFieldException e) {
//            e.printStackTrace();
//        } catch (IOException e) {
//            e.printStackTrace();
//        } finally {
//        }
//    }
//    private static Unsafe getUnsafe() throws NoSuchFieldException, IllegalAccessException {
//            Field f=Unsafe.class.getDeclaredField("theUnsafe");
//            f.setAccessible(true);
//            Unsafe unsafe= (Unsafe) f.get(null);
//            return unsafe;
//
//    }

//    ・四种引用
//    -》强引用
//    -》软引用（发生回收，内存不够：有可能被回收）
//    -》弱引用（一定会回收）
//    -》虚引用（必须配合引用队列 直接内存地址）
//    -》终结器引用（必须配合引用队列）

//    public static void main(String[] args){
//        // 强引用
//        String strongReference = new String("abc");
//
//        // 软引用 软引用(SoftReference)
////        如果一个对象只具有软引用，则内存空间充足时，垃圾回收器就不会回收它；如果内存空间不足了，
////        就会回收这些对象的内存。只要垃圾回收器没有回收它，该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。
////        注意：软引用对象是在jvm内存不够的时候才会被回收，我们调用System.gc()方法只是起通知作用，
////        JVM什么时候扫描回收对象是JVM自己的状态决定的。就算扫描到软引用对象也不一定会回收它，只有内存不够的时候才会回收。
//        ReferenceQueue<String> referenceQueue = new ReferenceQueue<>();
//        String str = new String("abc");
////        软引用可以和一个引用队列(ReferenceQueue)联合使用。如果软引用所引用对象被垃圾回收，JAVA虚拟机就会把这个软引用加入到与之关联的引用队列中。
//        SoftReference<String> softReference = new SoftReference<>(str, referenceQueue);
//
//        str = null;
//        // Notify GC
//        System.gc();
//
//        System.out.println(softReference.get()); // abc
//
//        Reference<? extends String> reference = referenceQueue.poll();
//        System.out.println(reference); //null
//
////    弱引用(WeakReference)
//    弱引用与软引用的区别在于：只具有弱引用的对象拥有更短暂的生命周期。
//    在垃圾回收器线程扫描它所管辖的内存区域的过程中，一旦发现了只具有弱引用的对象，
//    不管当前内存空间足够与否，都会回收它的内存。不过，由于垃圾回收器是一个优先级很低的线程，
//    因此不一定会很快发现那些只具有弱引用的对象。


//    }
//    字符串去重
    public static void main(String[] arg0 ) throws IOException {

//        -XX:+UseStringDeduplication
        // [a]
        String a1= new String("hello"); // 字符串去重 底层去重 frame-》Variables-》char[5] 的地址是一样的
        String a2= new String("hello"); // 字符串去重 底层去重 frame-》Variables-》char[5] 的地址是一样的
        System.out.println(a1==a2);// 但是a1 和 a2肯定不相同


    }

}
